﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WJ.Infrastructure.Util
{
    /// <summary>
    /// 日期时间方法集
    /// </summary>
    public static class DateTimeTool
    {

        public static readonly DateTime NetMinDate = new DateTime();
        /// <summary>
        /// Sql Server中SmallDateTime类型的最小值
        /// </summary>
        public static readonly DateTime MinSmallDate = new DateTime(1900, 1, 1);

        /// <summary>
        /// Sql Server中SmallDateTime类型的最大值
        /// </summary>
        public static readonly DateTime MaxSmallDate = new DateTime(2079, 6, 6);

        /// <summary>
        /// Sql Server中DateTime类型的最小值
        /// </summary>
        public static readonly DateTime MinDate = new DateTime(1753, 1, 1);

        /// <summary>
        /// Sql Server中DateTime类型的最大值
        /// </summary>
        public static readonly DateTime MaxDate = new DateTime(9999, 12, 31);

        /// <summary>
        /// 时间日期的空值
        /// </summary>
        /// <value>
        /// 1900-1-1 00:00:00
        /// </value>
        public static readonly DateTime BaseDate = MinSmallDate;

        /// <summary>
        /// 得到只有时间的值，日期为1900-1-1
        /// </summary>
        /// <param name="A_dtValue"></param>
        /// <returns></returns>
        public static DateTime GetTime(DateTime A_dtValue)
        {
            return new DateTime(
                    BaseDate.Year,
                    BaseDate.Month,
                    BaseDate.Day,
                    A_dtValue.Hour,
                    A_dtValue.Minute,
                    A_dtValue.Second,
                    A_dtValue.Millisecond);
        }
        /// <summary>
        /// 返回时间，不包含秒
        /// </summary>
        /// <param name="A_dtValue"></param>
        /// <returns></returns>
        public static DateTime GetTimeNonSecond(DateTime A_dtValue)
        {
            return new DateTime(
                    BaseDate.Year,
                    BaseDate.Month,
                    BaseDate.Day,
                    A_dtValue.Hour,
                    A_dtValue.Minute,
                    0,
                    0);
        }
        /// <summary>
        /// 判断时间是否为空值，，其中1900-1-1和000-1-1也默认为空值
        /// </summary>
        /// <param name="dt">The dt.</param>
        /// <returns><c>true</c> if [is null or empty] [the specified dt]; otherwise, <c>false</c>.</returns>
        public static bool IsNullOrEmpty(DateTime dt)
        {
            if (dt == default(DateTime) || dt == new DateTime(1900, 1, 1))
                return true;
            else
                return false;
        }
        /// <summary>
        ///	 得到只有日期的值
        /// </summary>
        /// <param name="dtSource"></param>
        /// <returns>去除Time值的DateTime</returns>
        public static DateTime GetDateOnly(DateTime dtSource)
        {
            return new DateTime(
                dtSource.Year,
                dtSource.Month,
                dtSource.Day);
        }
        /// <summary>
        /// 测试是否是日期格式
        /// </summary>
        /// <param name="dt">日期</param>
        /// <returns>返回是日期则返回true, 否则false</returns>
        public static bool IsDate(object dt)
        {
            try
            {
                System.DateTime.Parse(dt.ToString());
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 返回年中包括指定 DateTime 中的日期的星期
        /// </summary>
        /// <param name="date">日期</param>
        /// <returns>从 1 开始的一个整数，它表示年中包括 time 中的日期的星期。</returns>
        /// <remarks>
        /// 调用<see cref="System.Globalization.Calendar.GetWeekOfYear"/></remarks>
        public static int WeekOfYear(DateTime date)
        {
            //			DateTime first = date.AddDays(-1* date.DayOfYear+1);
            //			return (date.DayOfYear + 7 - Convert.ToInt32(first.DayOfWeek))/7 + 1;
            System.Globalization.CultureInfo myCI = new System.Globalization.CultureInfo("en-US");
            System.Globalization.Calendar myCal = myCI.Calendar;
            System.Globalization.CalendarWeekRule myCWR = myCI.DateTimeFormat.CalendarWeekRule;
            DayOfWeek myFirstDOW = myCI.DateTimeFormat.FirstDayOfWeek;
            return myCal.GetWeekOfYear(date, myCWR, myFirstDOW);
        }

        public static DateTime[] GetWeekDaysRange(int year, int week)
        {
            DateTime first = new DateTime(year, 1, 1);
            DateTime dt = first.AddDays(-(int)first.DayOfWeek);
            int days = week * 7 - (int)dt.DayOfWeek - 1;
            DateTime end = dt.AddDays(days);
            DateTime start;
            if (days > 7)
            {
                start = end.AddDays(-6);
            }
            else
            {
                start = dt;
            }
            return new DateTime[] { start, end };
        }

        public static DateTime[] GetWeekDaysRange(DateTime date)
        {
            return GetWeekDaysRange(date.Year, WeekOfYear(date));
        }

        public static DateTime[] GetWeekDays(int year, int week)
        {
            DateTime[] dateFromTo = GetWeekDaysRange(year, week);
            ArrayList days = new ArrayList();
            for (DateTime d = dateFromTo[0]; d <= dateFromTo[1]; d = d.AddDays(1))
                days.Add(d);
            DateTime[] allDaysInWeek = days.ToArray(typeof(DateTime)) as DateTime[];
            return allDaysInWeek;
        }

        public static DateTime[] GetWeekDays(DateTime date)
        {
            return GetWeekDays(date.Year, WeekOfYear(date));
        }


        /// <summary>
        /// 计算日期间隔时间
        /// </summary>
        /// <param name="dt1">开始日期</param>
        /// <param name="dt2">结束日期</param>
        /// <returns>
        /// <paramref name="dt2"/>减去<paramref name="dt1"/>
        /// </returns>
        public static DateSpan DatePeriod(DateTime dt1, DateTime dt2)
        {
            DateTime dt;
            if (dt1 > dt2)
            {
                dt = dt1;
                dt1 = dt2;
                dt2 = dt;
            }
            int seconds = dt2.Second - dt1.Second;
            int minutes = dt2.Minute - dt1.Minute;
            int hours = dt2.Hour - dt1.Hour;
            int days = dt2.Day - dt1.Day;
            int months = dt2.Month - dt1.Month;
            int years = dt2.Year - dt1.Year;
            if (seconds < 0)
            {
                minutes--;
                seconds += 60;
            }
            if (minutes < 0)
            {
                hours--;
                minutes += 60;
            }
            if (hours < 0)
            {
                days--;
                hours += 24;
            }
            if (days < 0)
            {
                months--;
                int previousMonth = (dt2.Month == 1) ? 12 : dt2.Month - 1;
                int year = (previousMonth == 12) ? dt2.Year - 1 : dt2.Year;
                days += DateTime.DaysInMonth(year, previousMonth);
            }
            if (months < 0)
            {
                years--;
                months += 12;
            }

            DateSpan ds = new DateSpan()
            {
                Years = years,
                Months = months,
                Days = days,
                Hours = hours,
                Minutes = minutes,
                Seconds = seconds
            };
            return ds;
        }

        /// <summary>
        /// 一天的开始时间
        /// </summary>
        /// <param name="date">传入日期</param>
        /// <returns>返回date参数,日期不变，时间为00:00:00</returns>
        public static DateTime BeginOfDay(DateTime date)
        {
            return new DateTime(date.Year, date.Month, date.Day, 0, 0, 0);
        }

        /// <summary>
        /// 一天的结束时间
        /// </summary>
        /// <param name="date">传入日期</param>
        /// <returns>返回date参数，日期不变，但是时间为23:59:59</returns>
        public static DateTime EndOfDay(DateTime date)
        {
            return new DateTime(date.Year, date.Month, date.Day, 23, 59, 59);
        }
        /// <summary>
        /// 一周的开始日
        /// </summary>
        /// <param name="date">日期</param>
        /// <returns>返回一周开始日期</returns>
        public static DateTime BeginOfWeek(DateTime date)
        {
            return (GetWeekDaysRange(date))[0];
        }
        /// <summary>
        /// 一周的结束日
        /// </summary>
        /// <param name="date">日期</param>
        /// <returns>返回一周结束日期</returns>
        public static DateTime EndOfWeek(DateTime date)
        {
            return (GetWeekDaysRange(date))[1];
        }
        /// <summary>
        /// 一月的开始日
        /// </summary>
        /// <param name="date">日期</param>
        /// <returns>返回一月开始日期</returns>
        public static DateTime BeginOfMonth(DateTime date)
        {
            return new DateTime(date.Year, date.Month, 1);
        }
        /// <summary>
        /// 一月的结束日
        /// </summary>
        /// <param name="date">日期</param>
        /// <returns>返回一月结束日期</returns>
        public static DateTime EndOfMonth(DateTime date)
        {
            return new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
        }

        /// <summary>
        /// 一年的开始日
        /// </summary>
        /// <param name="date">日期</param>
        /// <returns>返回一年开始日期</returns>
        public static DateTime BeginOfYear(DateTime date)
        {
            return new DateTime(date.Year, 1, 1);
        }
        /// <summary>
        /// 一年的结束日
        /// </summary>
        /// <param name="date">日期</param>
        /// <returns>返回一年结束日期</returns>
        public static DateTime EndOfYear(DateTime date)
        {
            return new DateTime(date.Year, 12, 31);
        }
        /// <summary>
        /// Int转换成Date
        /// </summary>
        /// <param name="intpara"></param>
        /// <returns>Datetime只有用到Date</returns>
        static public DateTime Int2Date(int intpara)
        {
            if (intpara < 36160 || intpara > 3652059)
                return new DateTime(1900, 1, 1, 0, 0, 0, 0);
            else
                return new DateTime(1970, 11, 8).AddDays(intpara - 719474);
        }

        /// <summary>
        /// Date转换成Int
        /// </summary>
        /// <param name="datepara">Datetime只有用到Date</param>
        /// <returns></returns>
        static public int Date2Int(DateTime datepara)
        {
            TimeSpan ts1 = new DateTime(1000, 1, 1) - datepara;
            TimeSpan ts2 = new DateTime(9999, 12, 31) - datepara;
            TimeSpan ts3 = datepara - new DateTime(1970, 11, 8);
            return ts3.Days + 719474;
        }

        /// <summary>
        /// Date转换成Int
        /// </summary>
        /// <param name="datepara">Datetime只有用到Date</param>
        /// <returns></returns>
        static public int Date2Int(object datepara)
        {
            int d = 0;
            try
            {
                d = Date2Int(DateTime.Parse(datepara.ToString()));
            }
            catch
            {
            }
            return d;
        }

        /// <summary>
        /// Int转换成Time
        /// </summary>
        /// <param name="intpara"></param>
        /// <returns>Datetime只有用到Time</returns>
        static public DateTime Int2Time(int intpara)
        {
            try
            {
                if (intpara > 86400)
                    return new DateTime(1900, 1, 1, 0, 0, 0, 0);
                else
                {
                    int h = 0, m = 0, s = 0;
                    h = (intpara - intpara % 3600) / 3600;
                    m = (intpara % 3600 - intpara % 3600 % 60) / 60;
                    s = intpara % 60;
                    return new DateTime(1900, 1, 1, h, m, s, 0);
                }
            }
            catch
            {
                return new DateTime(1900, 1, 1, 8, 8, 0, 0);

            }
        }
        /// <summary>
        /// Int转换成Time的String，格式为HH:mm
        /// </summary>
        /// <param name="A_iValue"></param>
        /// <returns></returns>
        static public string Int2TimeStr(int A_iValue)
        {
            return A_iValue == 0 ? "00:00" : A_iValue == 86400 ? "24:00" : Int2Time(A_iValue).ToString("HH:mm");
        }
        /// <summary>
        /// Time转换成Int
        /// </summary>
        /// <param name="datepara">Datetime只有用到Time</param>
        /// <returns></returns>
        static public int Time2Int(DateTime datepara)
        {
            int t = datepara.Hour * 3600 + datepara.Minute * 60 + datepara.Second;
            if (t > 86400) t = 86400;
            if (t < 0) t = 0;
            return t;
        }

        /// <summary>
        /// 日期转成string
        /// </summary>
        /// <param name="date">日期</param>
        /// <returns>返回string格式的日期，默认yyyy-MM-dd格式</returns>
        public static string Date2String(DateTime date)
        {
            if (date == new DateTime(1900, 1, 1) || date == DateTime.MinValue)
                return "0000-00-00";
            else
                return date.ToString("yyyy-MM-dd");
        }
        /// <summary>
        /// 日期转成string
        /// </summary>
        /// <param name="date">日期</param>
        /// <returns>返回string格式的日期，默认yyyy-MM-dd格式</returns>
        public static string Date2String(string date)
        {
            try
            {
                return Date2String(DateTime.Parse(date));
            }
            catch
            {
                return "0000-00-00";
            }
        }
        /// <summary>
        /// 时间转成string
        /// </summary>
        /// <param name="date">时间</param>
        /// <returns>返回string格式的时间，默认HH:mm格式</returns>	
        public static string Time2String(DateTime date)
        {
            if (date == new DateTime(1900, 1, 1) || date == DateTime.MinValue)
                return "";
            else if (date == new DateTime(1900, 1, 2, 0, 0, 0))
                return "00:00";
            else
                return date.ToString("HH:mm");
        }

        /// <summary>
        /// 设置星期的名称
        /// </summary>
        /// <param name="language">语言名名</param>
        public static void SetDateCultureInfo(string language)
        {
            System.Globalization.CultureInfo ci;
            string sLowerLang = language.ToLower();
            if (sLowerLang == "chn"
                || sLowerLang == "c"
                || sLowerLang == "chinese")
            {
                ci = new System.Globalization.CultureInfo("zh-CN");
                ci.DateTimeFormat.DayNames = new String[] { "日", "一", "二", "三", "四", "五", "六" };

            }
            else
            {
                ci = new System.Globalization.CultureInfo("en-US");
            }
            System.Threading.Thread.CurrentThread.CurrentCulture = ci;
        }

        public static DateTime GetBaseDate(DateTime datetime)
        {
            if (datetime == NetMinDate)
            {
                return BaseDate;
            }
            else
            {
                return datetime;
            }
        }


        public static DateTime Add(this DateTime datetime, DateTime source)
        {
            if (source == new DateTime() || source == DateTimeTool.BaseDate)
            {
                return datetime;
            }
            else
            {
                DateTime adjust = GetBaseDate(datetime);
                return adjust.Add(source.ToTimeSpan());
            }
        }
        public static DateTime ToDateTime(this TimeSpan span)
        {
            return DateTimeTool.BaseDate.Add(span);
        }

        public static TimeSpan ToTimeSpan(this DateTime datetime)
        {
            return datetime - DateTimeTool.BaseDate;
        }


        public static DateTime BaseTime(int hour, int minute = 0, int second = 0)
        {
            return new DateTime(BaseDate.Year, BaseDate.Month, BaseDate.Day, hour, minute, second);

        }

        /// <summary>
        /// 根据日期得到星期的描述
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static string GetWeekDay(DateTime dt)
        {
            DayOfWeek dayOfWeek = dt.DayOfWeek;
            string weekStr = "";
            switch (dayOfWeek)
            {
                case DayOfWeek.Monday:
                    weekStr = "周一";
                    break;
                case DayOfWeek.Tuesday:
                    weekStr = "周二";
                    break;
                case DayOfWeek.Wednesday:
                    weekStr = "周三";
                    break;
                case DayOfWeek.Thursday:
                    weekStr = "周四";
                    break;
                case DayOfWeek.Friday:
                    weekStr = "周五";
                    break;
                case DayOfWeek.Saturday:
                    weekStr = "周六";
                    break;
                case DayOfWeek.Sunday:
                    weekStr = "周日";
                    break;
            }
            return weekStr;
        }

        public static DateTime UnixTimeStampToDateTime(double unixTimeStamp)
        {
            // Unix timestamp is seconds past epoch
            System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
            dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime();
            return dtDateTime;
        }

        public static double ToUnixTimestamp(DateTime target)
        {
            return (TimeZoneInfo.ConvertTimeToUtc(target) -
                    new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc)).TotalSeconds;
        }

        public static DateTime JavaTimeStampToDateTime(double javaTimeStamp)
        {
            // Java timestamp is milliseconds past epoch
            System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
            dtDateTime = dtDateTime.AddMilliseconds(javaTimeStamp).ToLocalTime();
            return dtDateTime;
        }
    }

    /// <summary>
    /// 日期格式化原点
    /// </summary>
    public enum DatePartType
    {
        /// <summary>
        /// 返回秒
        /// </summary>
        Second = 0,
        /// <summary>
        /// 返回分钟
        /// </summary>
        Minute = 1,
        /// <summary>
        /// 返回小时
        /// </summary>
        Hour = 2,
        /// <summary>
        /// 返回天
        /// </summary>
        Day = 3,
        /// <summary>
        /// 返回月
        /// </summary>
        Month = 4,
        /// <summary>
        /// 返回年
        /// </summary>
        Year = 5
    }


    public class DateSpan
    {
        /// <summary>
        /// 年数
        /// </summary>
        public int Years
        {
            get;
            set;
        }
        /// <summary>
        /// 月数
        /// </summary>
        public int Months
        {
            get;
            set;
        }
        /// <summary>
        /// 日数
        /// </summary>
        public int Days
        {
            get;
            set;
        }
        /// <summary>
        /// 小时数
        /// </summary>
        public int Hours
        {
            get;
            set;
        }
        /// <summary>
        /// 分钟数
        /// </summary>
        public int Minutes
        {
            get;
            set;
        }
        /// <summary>
        /// 秒数
        /// </summary>
        public int Seconds
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        public DateSpan()
        {

        }
        /// <summary>
        /// 字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {

            StringBuilder sbText = new StringBuilder();

            if (this.Years != 0)
            {
                sbText.Append(this.Years.ToString());
                sbText.Append("STR_Year");
            }
            if (this.Months != 0)
            {
                sbText.Append(this.Years > 0 ? "," : "");
                sbText.Append(this.Months.ToString());
                sbText.Append("STR_Month");
            }
            if (this.Days != 0)
            {

                sbText.Append(this.Years > 0 || this.Months > 0 ? "," : "");
                sbText.Append(this.Days.ToString());
                sbText.Append("STR_Day");
            }
            return sbText.ToString();
        }
    }
}
